﻿using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Z.Nlayer.Domain.Base;
using Company.Project.Domain.MainModule.Interface;
using Company.Project.Domain.Model;
using Company.Project.Domain.Model.DTO.Manager;
using Z.Nlayer.Utility;

namespace Company.Project.Domain.MainModule
{
    public class Project_SYS_ModuleDomainServices : IProject_SYS_ModuleDomainServices
    {
        private readonly IProject_SYS_ModuleRepository _repository;
        private readonly IProject_SYS_ModuleActionRepository _moduleActionRepository;
        private readonly IProject_SYS_RoleActionRepository _roleActionRepository;

        public Project_SYS_ModuleDomainServices(IProject_SYS_ModuleRepository repository, IProject_SYS_ModuleActionRepository moduleActionRepository,
            IProject_SYS_RoleActionRepository roleActionRepository)
        {
            this._repository = repository;
            _moduleActionRepository = moduleActionRepository;
            _roleActionRepository = roleActionRepository;
        }
        public async Task<string> GetLoginRoleMenu(LoginUserDTO loginUser)
        {
            StringBuilder sMenu = new StringBuilder();
            //var modelList = (await
            //    _repository.GetManyAsync(new DirectSpecification<Project_SYS_Module>(x => !x.IsDeleted), true)).OrderBy(x => x.OrderID).ToList();
            var modelList =
                await _repository.GetLoginModule();
            if (modelList.Any())
            {
                var parentList = modelList.Where(m => m.PID == Guid.Empty).ToList();//获取大模块
                if (parentList != null)
                {
                    foreach (var pModule in parentList)
                    {//遍历大模块
                        var iModuleID = pModule.ID;
                        string sChildJson = InitMenu(iModuleID, modelList, loginUser);
                        if (sChildJson != "'menus':[\r\n]\r\n")
                        {//如果登录用户拥有该大模块权限
                            if (sMenu.Length == 0)
                            {
                                sMenu.AppendLine("{'menus':[");
                            }
                            sMenu.AppendLine("   { " +
                                             InitJsonItem(iModuleID.ToString(), pModule.ModuleName, pModule.ModuleUrl,
                                                 new List<Project_SYS_ModuleAction>(), null, pModule.ModuleCls));//添加大模块菜单
                            sMenu.AppendLine("    " + sChildJson);//添加子模块菜单
                            sMenu.AppendLine("},");
                        }
                    }
                }
                if (sMenu.Length > 0)
                {//添加最后一个]
                    int iDouHaoIndex = sMenu.ToString().LastIndexOf(',');
                    if (iDouHaoIndex != -1)
                    {
                        sMenu = sMenu.Remove(iDouHaoIndex, 1);
                    }
                    sMenu.Append("]}");
                }
            }
            return sMenu.ToString();
        }

        private string InitMenu(Guid iModuleID, IEnumerable<Project_SYS_Module> modulelist, LoginUserDTO loginUser)
        {
            StringBuilder sResult = new StringBuilder();
            List<Project_SYS_Module> childList = modulelist.Where(m => m.PID == iModuleID).OrderBy(x => x.OrderID).ToList();//获取子模块菜单
            if (childList.Any())
            {
                var userActionList = loginUser.UserActionList;//当前登录用户权限
                sResult.AppendLine("'menus':[");
                foreach (var module in childList)
                {
                    Guid iTempModuleID = module.ID;
                    if (!userActionList.Exists(m => m.ModuleID == iTempModuleID))
                    {
                        //如果用户没有该模块的权限 则检查是否有子模块，否则进入下一个循环
                        var childmodule = modulelist.Where(m => m.PID == iTempModuleID).OrderBy(x => x.OrderID).ToList();//获取三级子模块菜单
                        if (childmodule.Any())
                        {
                            if (userActionList.Exists(m => childmodule.Select(x => x.ID).Contains(m.ModuleID)))
                            {
                                sResult.Append("    {" +
                                               InitChildModuleJsonItem(iTempModuleID.ToString(), module.ModuleName,
                                                   module.ModuleUrl, childmodule, userActionList, module.ModuleCls));
                                sResult.AppendLine("},");
                            }
                        }
                        else
                        {
                            continue;
                        }
                    }
                    else
                    {
                        sResult.Append("    {" + InitJsonItem(iTempModuleID.ToString(), module.ModuleName, module.ModuleUrl, module.ModuleActions, userActionList, module.ModuleCls));
                        sResult.AppendLine("},");
                    }
                }
                if (childList.Any())
                {
                    sResult.AppendLine("]");
                }
            }
            if (sResult.Length > 0)
            {//添加最后一个]
                int iDouHaoIndex = sResult.ToString().LastIndexOf(',');
                if (iDouHaoIndex != -1)
                {
                    sResult = sResult.Remove(iDouHaoIndex, 1);
                }
            }
            return sResult.ToString();
        }
        private string InitJsonItem(string sID, string menuname, string url, List<Project_SYS_ModuleAction> modelActions, List<RoleActionDTO> userActionList,string ModuleCls)
        {
            StringBuilder sResult = new StringBuilder();
            //sResult.AppendLine("{");
            sResult.Append("'menuid':'" + sID + "',");
            sResult.Append("'menuname':'" + menuname + "',");
            sResult.Append("'modulecls':'" + ModuleCls + "',");
            sResult.Append("'url':'" + url + "',");
            sResult.Append("'ismodule':false,");
            if (userActionList != null)
            {
                sResult.AppendLine("'menus':[");
                if (modelActions.Any())
                {
                    var Weight = 0;
                    modelActions.Where(x => !x.IsDeleted && x.ShowEnum).ToList().ForEach(x =>
                    {
                        var weightitem = userActionList.FirstOrDefault(m => m.ModuleID == Guid.Parse(sID));
                        if (weightitem != null)
                        {
                            Weight = Weight | weightitem.Weight;
                            if ((Weight & x.Weight) == x.Weight)
                            {
                                sResult.Append("    {");
                                sResult.Append("'menuid':'" + x.ID + "',");
                                sResult.Append("'menuname':'" + x.ActionName + "',");
                                sResult.Append("'url':'" + x.ActionUrl + "',");
                                sResult.AppendLine("},");
                            }
                        }
                    });
                }
                sResult.Append("]");
            }
            //sResult.AppendLine("}");
            return sResult.ToString();
        }
        private string InitChildModuleJsonItem(string sID, string menuname, string url, List<Project_SYS_Module> childModule, List<RoleActionDTO> userActionList, string ModuleCls)
        {
            StringBuilder sResult = new StringBuilder();
            //sResult.AppendLine("{");
            sResult.Append("'menuid':'" + sID + "',");
            sResult.Append("'menuname':'" + menuname + "',");
            sResult.Append("'modulecls':'" + ModuleCls + "',");
            sResult.Append("'url':'" + url + "',");
            sResult.Append("'ismodule':true,");
            if (childModule != null)
            {
                sResult.AppendLine("'menus':[");
                if (childModule.Any())
                {
                    childModule.Where(x => !x.IsDeleted && userActionList.Select(y => y.ModuleID).Contains(x.ID)).ToList().ForEach(x =>
                    {
                        sResult.Append("    {" + InitJsonItem(x.ID.ToString(), x.ModuleName, x.ModuleUrl, x.ModuleActions, userActionList, x.ModuleCls));
                        sResult.AppendLine("},");
                    });
                }
                sResult.Append("]");
            }
            //sResult.AppendLine("}");
            return sResult.ToString();
        }

        public async Task AddModule(Project_SYS_Module item)
        {
            if (item.OrderID < 0)
            {
                item.OrderID = 0;
            }
            //递归获取所有实体
            var all =(await _repository.GetModuleByRecursive()).ToList();
            if (item.ID == Guid.Empty)
            {
                if (await 
                    _repository.ExistsAsync(
                        new DirectSpecification<Project_SYS_Module>(x => x.ModuleName == item.ModuleName && !x.IsDeleted)))
                {
                    throw new CustomException("当前已有同名模块,请确保模块名称唯一");
                }
                item.ID = Guid.NewGuid();
                if (item.PID != Guid.Empty)
                {
                    var father = all.FirstOrDefault(x => x.ID == item.PID);
                    if (father == null)
                    {
                        throw new CustomException("选择的父级模块没有找到,请重试!");
                    }
                    else if (father.Level > 1)
                    {
                        throw new CustomException("只能选择一二级作为父级模块,请重试!");
                    }
                    
                    if (await _moduleActionRepository.ExistsAsync(new DirectSpecification<Project_SYS_ModuleAction>(x => !x.IsDeleted && x.ModuleID == father.ID)))
                    {
                        throw new CustomException("不能选择有功能的模块作为父级,请重试!");
                    }
                    if (father.Level > 0 && (item.ModuleActions == null || !item.ModuleActions.Any()))
                    {
                        throw new CustomException("请至少添加一个功能!");
                    }
                    if (item.ModuleActions != null && item.ModuleActions.Any())
                    {
                        if (item.ModuleActions.GroupBy(l => l.ActionName).Any(g => g.Count() > 1))
                        {
                            throw new CustomException("当前已有同名功能,请确保功能名称唯一!");
                        }
                        if (item.ModuleActions.GroupBy(l => l.OrderID).Any(g => g.Count() > 1))
                        {
                            throw new CustomException("请确保功能排序编号唯一!");
                        }
                        item.ModuleActions.ForEach(x =>
                        {
                            x.ID = Guid.NewGuid();
                            x.ModuleID = item.ID;
                            if (x.OrderID < 0)
                            {
                                x.OrderID = 0;
                            }
                            x.Weight = Convert.ToInt32(Math.Pow(2, (x.OrderID)));
                            if (string.IsNullOrEmpty(x.ActionName) || string.IsNullOrEmpty(x.ActionUrl))
                            {
                                throw new CustomException("功能名称和地址必须填写!");
                            }
                        });
                    }
                }
                else
                {
                    item.ModuleActions = null;
                }
                item.CreateTime = DateTime.Now;
                _repository.Add(item);
            }
            else
            {
                var old =await _repository.GetByConditionAsync(new DirectSpecification<Project_SYS_Module>(x => x.ID == item.ID));
                var me = all.FirstOrDefault(x => x.ID == item.ID);
                if (old == null || old.IsDeleted)
                {
                    throw new CustomException("没有查询到该模块,请重试!");
                }
                if (all.Exists(x => x.ModuleName == item.ModuleName && !x.IsDeleted && x.ID != item.ID))
                {
                    throw new CustomException("当前已有同名模块,请确保模块名称唯一");
                }
                if (item.PID != Guid.Empty)
                {
                    var father = all.FirstOrDefault(x => x.ID == item.PID);
                    if (father == null)
                    {
                        throw new CustomException("选择的父级模块没有找到,请重试!");
                    }
                    if (me.ID == father.ID)
                    {
                        throw new CustomException("不能选择自身作为父级,请重试!");
                    }
                    if (!CheckFatherId(all, me.ID, father.ID))
                    {
                        throw new CustomException("不能选择自身子级作为父级,请重试!");
                    }
                    if ((await _moduleActionRepository.ExistsAsync(new DirectSpecification<Project_SYS_ModuleAction>(x => !x.IsDeleted && x.ModuleID== item.PID))))
                    {
                        throw new CustomException("不能选择有功能的模块作为父级,请重试!");
                    }
                    var myLevel = GetSunLevel(all, me.ID) + father?.Level;
                    if (myLevel > 1)
                    {
                        throw new CustomException("模块管理只能设置三级,请重试!");
                    }
                    if (father.Level > 1)
                    {
                        throw new CustomException("只能选择一二级作为父级模块,请重试!");
                    }
                    if (father.Level > 0 && (item.ModuleActions == null || !item.ModuleActions.Any()))
                    {
                        throw new CustomException("请至少添加一个功能!");
                    }
                    if (item.ModuleActions != null && item.ModuleActions.Any())
                    {
                        if (item.ModuleActions.GroupBy(l => l.ActionName).Any(g => g.Count() > 1))
                        {
                            throw new CustomException("当前已有同名功能,请确保功能名称唯一!");
                        }
                        if (item.ModuleActions.GroupBy(l => l.OrderID).Any(g => g.Count() > 1))
                        {
                            throw new CustomException("请确保排序编号唯一!");
                        }
                    }
                }
                else
                {
                    if (item.ModuleActions != null && item.ModuleActions.Any())
                    {
                        throw new CustomException("不能将含有功能的模块变为顶级模块,请先删除功能!");
                    }
                }
                old.OrderID = item.OrderID;
                old.ModuleName = item.ModuleName;
                old.ModuleCls = item.ModuleCls;
                old.PID = item.PID;
                _repository.Update(old, x => x.OrderID, x => x.ModuleName, x => x.PID);
                var RoleChange = new List<dynamic>();
                var delitem = new List<dynamic>();
                if (item.ModuleActions != null && item.ModuleActions.Any())
                {
                    var keys = await _moduleActionRepository.GetManyAsync(
                        new DirectSpecification<Project_SYS_ModuleAction>(x => !x.IsDeleted && x.ModuleID == old.ID));
                    var oldweight = 0;
                    item.ModuleActions.ForEach(x =>
                    {
                        x.ModuleID = item.ID;
                        x.Weight = keys.FirstOrDefault(y => y.ID == x.ID)?.Weight ?? 0;
                        if (x.OrderID < 0)
                        {
                            x.OrderID = 0;
                        }
                        oldweight = x.Weight;
                        x.Weight = Convert.ToInt32(Math.Pow(2, (x.OrderID)));
                        if (oldweight != x.Weight)
                        {
                            if (x.ID != Guid.Empty)
                            {
                                RoleChange.Add(new {ModuleId = item.ID, ActionId = x.ID, Weight = x.Weight - oldweight});
                            }
                        }
                        if (string.IsNullOrEmpty(x.ActionName) || string.IsNullOrEmpty(x.ActionUrl))
                        {
                            throw new CustomException("功能名称和地址必须填写!");
                        }
                        if (x.ID == Guid.Empty)
                        {
                            x.ID = Guid.NewGuid();
                            _moduleActionRepository.Add(x);
                        }
                        else
                        {
                            if (keys != null && keys.Any())
                            {
                                var select = keys.FirstOrDefault(y => y.ID == x.ID);
                                if (select != null)
                                {
                                    select.ActionName = x.ActionName;
                                    select.ActionCls = x.ActionCls;
                                    select.ActionFun = x.ActionFun;
                                    select.ActionUrl = x.ActionUrl;
                                    select.OrderID = x.OrderID;
                                    select.ShowEnum = x.ShowEnum;
                                    select.Weight = x.Weight;
                                    _moduleActionRepository.Update(select, y => y.ActionName, y => y.ActionCls,
                                        y => y.ActionFun,
                                        y => y.ActionUrl, y => y.OrderID, y => y.ShowEnum);
                                }
                            }
                        }
                    });
                    var onlyid = item.ModuleActions.Where(y => y.ID != Guid.Empty).Select(y => y.ID);
                    (await _moduleActionRepository.GetManyAsync(
                        new DirectSpecification<Project_SYS_ModuleAction>(
                            x => !onlyid.Contains(x.ID) && x.ModuleID == old.ID && !x.IsDeleted)))
                        .Select(x => new {x.ID, x.ModuleID, x.Weight}).ToList().ForEach(x =>
                        {
                            delitem.Add(new {x.ID, x.ModuleID, x.Weight});
                        });
                    if (delitem.Any())
                    {
                        _moduleActionRepository.LogicDelete(
                            new DirectSpecification<Project_SYS_ModuleAction>(
                                x => !onlyid.Contains(x.ID) && x.ModuleID == old.ID && !x.IsDeleted));
                        delitem.ForEach(x =>
                        {
                            RoleChange.Add(new {ModuleId = x.ModuleID, ActionId = x.ID, Weight = 0 - x.Weight});
                        });
                    }
                }
                else
                {
                    //删除所有
                    (await _moduleActionRepository.GetManyAsync(
                        new DirectSpecification<Project_SYS_ModuleAction>(
                            x => x.ModuleID == old.ID && !x.IsDeleted)))
                        .Select(x => new {x.ID, x.ModuleID, x.Weight}).ToList().ForEach(x =>
                        {
                            delitem.Add(new {x.ID, x.ModuleID, x.Weight});
                        });
                    if (delitem.Any())
                    {
                        _moduleActionRepository.LogicDelete(
                            new DirectSpecification<Project_SYS_ModuleAction>(
                                x => x.ModuleID == old.ID && !x.IsDeleted));
                        delitem.ForEach(x =>
                        {
                            RoleChange.Add(new {ModuleId = x.ModuleID, ActionId = x.ID, Weight = 0 - x.Weight});
                        });
                    }
                }
                if (RoleChange.Any())
                {
                    //变更角色-功能权重
                    var modules = RoleChange.Select(y => (Guid) y.ModuleId);
                   (await _roleActionRepository.GetManyAsync(
                        new DirectSpecification<Project_SYS_RoleAction>(
                            x => modules.Contains(x.ModuleID)))).ToList().ForEach(
                                x =>
                                {
                                    RoleChange.ForEach(y =>
                                    {
                                        if (x.ModuleID == y.ModuleId)
                                        {
                                            x.Weight += y.Weight;
                                            _roleActionRepository.Update(x, z => z.Weight);
                                        }
                                    });
                                });
                }
            }
        }

        int GetSunLevel(List<RecursiveModuleDTO> all, Guid Id)
        {
            if (!all.Exists(x => x.PID == Id))
            {
                return 0;
            }
            else
            {
                var len = 1;
                var chd = all.Where(x => x.PID == Id);
                chd.ToList().ForEach(x =>
                {
                    if (GetSunLevel(all, x.ID) != 0)
                    {
                        len = len + GetSunLevel(all, x.ID);
                        return;
                    }
                });
                return len;
            }
        }

        bool CheckFatherId(List<RecursiveModuleDTO> all, Guid Id, Guid PId)
        {
            var father = all.FirstOrDefault(x => x.ID == PId);
            if (father == null)
            {
                return true;
            }
            if (father.ID == Id)
            {
                return false;
            }
            if (father.PID != Guid.Empty)
            {
                var gfather = all.FirstOrDefault(x => x.ID == father.PID);
                if (gfather == null)
                {
                    return true;
                }
                else
                {
                    if (gfather.ID == Id)
                    {
                        return false;
                    }
                    return CheckFatherId(all, Id, gfather.PID);
                }
            }
            return true;
        }

        public async Task<IEnumerable<string>> DelModule(IEnumerable<Guid> delId)
        {
            _repository.LogicDelete(
                new DirectSpecification<Project_SYS_Module>(y => delId.Contains(y.ID)));
            var delModule =
                (await
                    _repository.GetManyAsync(
                        new DirectSpecification<Project_SYS_Module>(y => delId.Contains(y.ID))));
            return delModule.Select(x => x.ModuleName);
        }
    }
}
